//=============================================================================
// filename: interface.cpp
// description: crap
// autor: Jay Tomten (jaytomten@gmail.com)
//=============================================================================

#include <SDL/SDL_image.h>
#include <GL/gl.h>
#include <SDL/SDL.h>
#include <iostream>
#include <string>
#include "game.h"
#include "interface.h"
#include "player.h"

//=============================================================================
// Interface() - constructor
Interface::Interface()
    {
    // nothing to do
    }

//=============================================================================
// ~Interface() - destructor
Interface::~Interface()
    {
    menu.clear();
    messages.clear();
    bubble.clear();

    delete &fontTitle32;
    delete &fontTitle72;
    delete &fontMain32;
    delete &fontMain16;

    glDeleteTextures(1, &fadetop);
    glDeleteTextures(1, &presents);
    glDeleteTextures(1, &retreat);

    }

//=============================================================================
// Interface() - alt constructor
bool Interface::Init(Game *e, int t, list<int> *l, Stats *s)
    {

    cout << "UI initialization... ";

    bool alive = true;
    if(!menu.empty())  menu.clear();  // main menu

    // load textures for UI
    fadetop = 0;
    presents = 0;
    retreat = 0;
    SDL_Surface *temp;
    temp = IMG_Load("../res/fadetop.png");
    if  (temp->w > 0)
        {
        glDeleteTextures(1, &fadetop);
        glGenTextures(1, &fadetop); // lets build the texture!
        glBindTexture(GL_TEXTURE_2D, fadetop);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, temp->w, temp->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp->pixels);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        }
    temp = IMG_Load("../res/presents.png");
    if  (temp->w > 0)
        {
        // glDeleteTextures(1, &presents);
        glGenTextures(1, &presents); // lets build the texture!
        glBindTexture(GL_TEXTURE_2D, presents);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, temp->w, temp->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp->pixels);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        }
    temp = IMG_Load("../res/retreat.png");
    if  (temp->w > 0)
        {
        // glDeleteTextures(1, &retreat);
        glGenTextures(1, &retreat); // lets build the texture!
        glBindTexture(GL_TEXTURE_2D, retreat);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, temp->w, temp->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp->pixels);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        }
    SDL_FreeSurface(temp);

    // load fonts for UI
    if (TTF_Init() == -1) cout << "Unable to initialize SDL_ttf: " << TTF_GetError() << endl;
    fontTitle32 = TTF_OpenFont("../res/guevara.ttf", 32);
    if(fontTitle32 != NULL) alive = true;
    else alive = false;
    fontTitle72 = TTF_OpenFont("../res/guevara.ttf", 72);
    if(fontTitle72 != NULL) alive = true;
    else alive = false;
    fontMain32 = TTF_OpenFont("../res/futured.ttf", 32);
    if(fontMain32 != NULL) alive = true;
    else alive = false;
    fontMain16 = TTF_OpenFont("../res/futured.ttf", 16);
    if(fontMain16 != NULL) alive = true;
    else alive = false;
    cout << "fonts loaded... ";

    // setup basic class vars
    rEngine = e;
    player = t;
    rEvents = l;
    rStats = s;
    width = rEngine->gScreen.width;
    height = rEngine->gScreen.height;

    // load the main menu
    Vertex *v = new Vertex();
    if  (rEngine->state == GAME_MAIN_MENU
    ||   rEngine->state == GAME_LOADING
    ||   rEngine->state == GAME_MULTI_LOCAL_P1_WIN
    ||   rEngine->state == GAME_MULTI_LOCAL_P2_WIN
    ||   rEngine->state == GAME_SINGLE_LOSE
    ||   rEngine->state == GAME_SINGLE_TOTAL_VICTORY)
        {
        BuildMenuItem(v->Make((width / 2), (height / 2) + 70.0f, 0.0f), "Solo Game",   SELECT_NEW_SOLO_GAME,  MENU_STATE_MM);
        BuildMenuItem(v->Make((width / 2), (height / 2) + 105.0f, 0.0f), "Versus Game", SELECT_NEW_MULTI_GAME, MENU_STATE_MM);
        // BuildMenuItem(v->Make((width / 2), (height / 2) - 110.0f, 0.0f), "Options",     0,                     MENU_STATE_MM);
        // BuildMenuItem(v->Make((width / 2), (height / 2) - 75.0f, 0.0f),  "Credits",     0,                     MENU_STATE_MM);
        BuildMenuItem(v->Make((width / 2), (height / 2) + 140.0f, 0.0f),  "Exit",        SELECT_EXIT_GAME,      MENU_STATE_MM);
        cout << "main menu built... ";
        }

    // load the game menu
    else if (rEngine->state == GAME_SINGLE_PLAYER
    ||       rEngine->state == GAME_MULTI_PLAYER_LOCAL
    ||       rEngine->state == GAME_SINGLE_WIN)
        {
        BuildMenuItem(v->Make(25, (height / 2) + 60.0f, 0.0f), "Infantry",        SELECT_BUILD_INF, MENU_STATE_GM);
        BuildMenuItem(v->Make(25, (height / 2) + 75.0f, 0.0f), "Engineer",        SELECT_BUILD_ENG, MENU_STATE_GM);
        BuildMenuItem(v->Make(25, (height / 2) + 90.0f, 0.0f), "Medic",           SELECT_BUILD_MED, MENU_STATE_GM);
        BuildMenuItem(v->Make(25, (height / 2) + 105.0f, 0.0f), "EOD",            SELECT_BUILD_EOD, MENU_STATE_GM);
        BuildMenuItem(v->Make(25, (height / 2) + 120.0f, 0.0f), "Special Forces", SELECT_BUILD_SF,  MENU_STATE_GM);
        BuildMenuItem(v->Make(25, (height / 2) + 150.0f, 0.0f), "End Match",      SELECT_END_MATCH, MENU_STATE_GM);
        // BuildMenuItem(v->Make(25, (height / 2) + 150.0f, 0.0f),"Exit game",       SELECT_EXIT_GAME, MENU_STATE_GM);
        cout << " game menu built... ";
        }
    delete v;

    cout << "success.\n";
    return alive;

    }

//=============================================================================
// Update() - update the user interface - waaaaay inefficient
bool Interface::Update(float d)
    {

    // update message position and color
    for(list<MessageItem>::iterator i = messages.begin(); i != messages.end(); i++)
        {
        if(i->pos.x != i->des.x || i->pos.y != i->des.y) Move(d, i);
        if(i->col.a > 0.9f) i->col.a -= d / 10.0f;
        else i->col.a -= d / 2;
        if(i->col.a < 0.0f) i->col.a = 0.0f;
        }

    // update bubble color
    for(list<MessageItem>::iterator i = bubble.begin(); i != bubble.end(); i++)
        {
        // if(i->pos.x != i->des.x || i->pos.y != i->des.y) Move(d, i);
        if(i->col.a > 0.9f) i->col.a -= d / 20.0f;
        else i->col.a -= d / 2;
        if(i->col.a < 0.0f) i->col.a = 0.0f;
        }

    // move menu items and see where the menu is at, also check the mouse...
    bool menuItemSelected = false;
    bool mouseOver = false;
    for (list<MenuItem>::iterator i = menu.begin(); i != menu.end(); i++)
        {
        if(i->pos.x != i->des.x || i->pos.y != i->des.y) Move(d, i);
        if(i->sel) menuItemSelected = true;
        if(rEngine->gInput.mouseState.x > i->pos.x && rEngine->gInput.mouseState.x < i->pos.x + i->wid && rEngine->gInput.mouseState.y < i->pos.y && rEngine->gInput.mouseState.y > i->pos.y - i->hei) mouseOver = true;
        }

    KeyInput *rKeys = NULL;
    if  (player == PLAYER_1) rKeys = &rEngine->gInput.keyStatePlayer1;
    else if(player == PLAYER_2) rKeys = &rEngine->gInput.keyStatePlayer2;

    // now process the events on each item in our menu
    for (list<MenuItem>::iterator i = menu.begin(); i != menu.end(); i++)
        {
        // process keybord events
        if(rKeys->down.active && !rKeys->down.used && menuItemSelected)   // do the down key
            {
            if(i->sel)
                {
                rKeys->down.used = true;
                if(i != menu.end())
                    {
                    i->sel = false;
                    i++;
                    if(i != menu.end()) i->sel = true;
                    }
                }
            }
        if(rKeys->down.active && !rKeys->down.used && !menuItemSelected) rEvents->push_back(SELECT_CAMERA_OUT); // if nothing selected
        if(rKeys->up.active && !rKeys->up.used && menuItemSelected)   // do the up key
            {
            if(i->sel)
                {
                rKeys->up.used = true;
                if(i != menu.begin())
                    {
                    i->sel = false;
                    i--;
                    i->sel = true;
                    }
                }
            }
        if(rKeys->up.active && !rKeys->up.used && !menuItemSelected) rEvents->push_back(SELECT_CAMERA_IN); // if nothing is selected
        if(rKeys->right.active) rEvents->push_back(SELECT_CAMERA_RIGHT); // do the right key
        if(rKeys->left.active)  rEvents->push_back(SELECT_CAMERA_LEFT); // do the left key
        if(rKeys->select.active && !rKeys->select.used && menuItemSelected)   // do the select key
            {
            if  (i->sel)
                {
                rEngine->stateTimer = 0.0f;
                rKeys->select.used = true;
                i->sel = false;
                rEvents->push_back(i->act);
                }
            }
        if  (rKeys->select.active && !rKeys->select.used && !menuItemSelected)   // if still not used...
            {
            list<MenuItem>::iterator i = menu.begin();
            rKeys->select.used = true;
            menuItemSelected = true;
            i->sel = true;
            }
        if  (rKeys->cancel.active && !rKeys->cancel.used && menuItemSelected && i->sel == true)   // do the cancel key
            {
            i->sel = false;
            menuItemSelected = false;
            rKeys->cancel.used = true;
            }

        // check for mouse events
        if  (mouseOver && rEngine->state != GAME_MULTI_PLAYER_LOCAL && rEngine->state != GAME_MULTI_LOCAL_P1_WIN && rEngine->state != GAME_MULTI_LOCAL_P2_WIN)
            {
            if  (rEngine->gInput.mouseState.x > i->pos.x && rEngine->gInput.mouseState.x < i->pos.x + i->wid && rEngine->gInput.mouseState.y < i->pos.y && rEngine->gInput.mouseState.y > i->pos.y - i->hei)
                {
                i->sel = true;
                if  (rEngine->gInput.mouseState.left.active && !rEngine->gInput.mouseState.left.used)
                    {
                    rEngine->stateTimer = 0.0f;
                    rEvents->push_back(i->act);
                    rEngine->gInput.mouseState.left.used = true;
                    }
                }
            else
                {
                i->sel = false;
                }
            }

        //
        // change the color of selected items
        //
        if  (i->sel == true)
            {
            i->col.g = 0.0;
            i->col.b = 0.0;
            }
        else
            {
            i->col.g = 1.0;
            i->col.b = 1.0;;
            }

        } // end for


    // escape transition/story/help state screens by overriding the stateTimer
    if  ((rEngine->gInput.keyStatePlayer1.escape.active && !rEngine->gInput.keyStatePlayer1.escape.used)
    ||   (rEngine->gInput.keyStatePlayer2.escape.active && !rEngine->gInput.keyStatePlayer2.escape.used))
        {
        rEngine->stateTimer = 999.0f;
        }

    return true;

    }

//=============================================================================
// Draw() - draw user interface
void Interface::Draw()
    {
    // delete dead bubbles 1 at a time -- there is probably a better way
    for (list<MessageItem>::iterator i = bubble.begin(); i != bubble.end(); ++i)
        {
        if(i->col.a <= 0.0f)
            {
            bubble.erase(i);
            break;
            }
        }

    // display bubbles
    for (list<MessageItem>::iterator i = bubble.begin(); i != bubble.end(); ++i)
        {
        glColor4f(1.0f, 1.0f, 1.0f, i->col.a);
        DrawImage3D(i->pos.x - 0.2f, i->pos.y - 0.2f, i->pos.z, &fadetop, i->wid + (0.4f * 40.0f), i->hei + (0.4f * 40.0f)); // the bubble
        glPushMatrix();
        glLineWidth(2.0f);
        glColor4f(1.0f, 1.0f, 1.0f, i->col.a);
        glBegin(GL_LINES);
        glVertex3f(i->pos.x + (i->wid / 40) + 0.2f, i->pos.y + (i->hei / 40) + 0.2f, i->pos.z);
        glVertex3f(i->pos.x + (i->wid / 40) + 0.2f, i->pos.y - 0.2f,                 i->pos.z);
        glVertex3f(i->pos.x - 0.2f,                 i->pos.y - 0.2f,                 i->pos.z);
        glVertex3f(i->pos.x - 0.2f,                 i->pos.y + (i->hei / 40) + 0.2f, i->pos.z);
        glVertex3f(i->pos.x + (i->wid / 40) + 0.2f, i->pos.y - 0.2f,                 i->pos.z);
        glVertex3f(i->pos.x + 0.4f,                 i->pos.y - 0.2f,                 i->pos.z);
        glVertex3f(i->pos.x - 0.2f,                 i->pos.y - 0.2f,                 i->pos.z);
        glVertex3f(i->pos.x + 0.2f,                 i->pos.y - 0.2f,                 i->pos.z);
        glVertex3f(i->pos.x - 0.2f,                 i->pos.y + (i->hei / 40) + 0.2f, i->pos.z);
        glVertex3f(i->pos.x + (i->wid / 40) + 0.2f, i->pos.y + (i->hei / 40) + 0.2f, i->pos.z);
        glVertex3f(i->pos.x + 0.2f,                 i->pos.y - 0.4f,                 i->pos.z);
        glVertex3f(i->pos.x + 0.2f,                 i->pos.y - 0.2f,                 i->pos.z);
        glVertex3f(i->pos.x + 0.2f,                 i->pos.y - 0.4f,                 i->pos.z);
        glVertex3f(i->pos.x + 0.4f,                 i->pos.y - 0.2f,                 i->pos.z);
        glEnd();
        glPopMatrix();
        glColor4f(i->col.r, i->col.g, i->col.b, i->col.a);
        DrawImage3D(i->pos.x, i->pos.y, i->pos.z, &i->tex, i->wid, i->hei); // the text
        }

    // now lets do 2D drawing
    if  (player != PLAYER_0)
        {

        // delete dead messages 1 at a time -- there is probably a better way
        for (list<MessageItem>::iterator i = messages.begin(); i != messages.end(); ++i)
            {
            if(i->col.a <= 0.0f)
                {
                messages.erase(i);
                break;
                }
            }

        // display messages
        if(rEngine->state != GAME_MAIN_MENU
        && rEngine->state != GAME_LOADING
        && rEngine->state != GAME_CLOSING
        && rEngine->state != GAME_STORY)
            {
            for (list<MessageItem>::iterator i = messages.begin(); i != messages.end(); ++i)
                {
                //if(i->pos.x != i->des.x || i->pos.y != i->des.y) Move(d, i);
                glColor4f(i->col.r, i->col.g, i->col.b, i->col.a);
                DrawImage2D(i->pos.x, i->pos.y, i->pos.z, &i->tex, i->wid, i->hei);
                }
            }

        // draw the menu items with fancy box thing, texture first
        if(rEngine->state != GAME_LOADING && rEngine->state != GAME_CLOSING)
            {
            float posx = 0.0f;
            float w = 0.0f;
            for (list<MenuItem>::iterator i = menu.begin(); i != menu.end(); ++i)
                {
                if(i->pos.x > posx) posx = i->pos.x;
                if(i->wid > w) w = i->wid;
                }
            posx -= 10.0f;
            w +=    20.0f;
            glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
            DrawImage2D(posx, height, 0.0f, &fadetop, w, ((height / 2) - 1));

            // draw the cool lines
            glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
            glPushMatrix();
            glLineWidth(2.0f);
            glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
            Go2D();
            glBegin(GL_LINES);
            glVertex3f(posx,        height / 2, 0.0f);
            glVertex3f(posx,        0.0f,       0.0f);
            glVertex3f(posx + w,    height / 2, 0.0f);
            glVertex3f(posx + w,    0.0f,       0.0f);
            glEnd();
            Go3D();
            glPopMatrix();

            // finally draw the text
            for (list<MenuItem>::iterator i = menu.begin(); i != menu.end(); ++i)
                {
                glColor4f(i->col.r, i->col.g, i->col.b, i->col.a);
                DrawImage2D(i->pos.x, i->pos.y, i->pos.z, &i->tex, i->wid, i->hei);
                }
            }

        // now draw stats and stuff...
        static char c[50];
        if(rEngine->state != GAME_MAIN_MENU && rEngine->state != GAME_LOADING && rEngine->state != GAME_CLOSING && rEngine->state != GAME_STORY)
            {
            glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
            sprintf(c, "Units: %i   Taxing: %4.2f IPS", rStats->units, rStats->units * 0.3);
            DrawString2D(5.0f, 20.0f, 0.0f, c, FONT_MAIN16);
            sprintf(c, "FOBs: %i   Earning: %4.2f IPS", rStats->fobs, rStats->fobs * 1.6);
            DrawString2D(5.0f, 35.0f, 0.0f, c, FONT_MAIN16);
            sprintf(c, "Kills: %i   Score: %i", rStats->kills, rStats->points);
            DrawString2D(5.0f, 50.0f, 0.0f, c, FONT_MAIN16);
            if(rStats->influence > 0.0) glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
            else glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
            sprintf(c, "Influence: %4.2f", rStats->influence);
            DrawString2D(5.0f, 80.0f, 0.0f, c, FONT_MAIN32);
            }
        if(rEngine->state == GAME_SINGLE_WIN || rEngine->state == GAME_SINGLE_TOTAL_VICTORY || (rEngine->state == GAME_MULTI_LOCAL_P1_WIN && rStats->type == PLAYER_1) || (rEngine->state == GAME_MULTI_LOCAL_P2_WIN && rStats->type == PLAYER_2))
            {
            glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
            DrawString2D(5.0f, 155.0f, 0.0, "Winner!", FONT_TITLE72);
            }
        else if(rEngine->state == GAME_SINGLE_LOSE || (rEngine->state == GAME_MULTI_LOCAL_P1_WIN && rStats->type == PLAYER_2) || (rEngine->state == GAME_MULTI_LOCAL_P2_WIN && rStats->type == PLAYER_1))
            {
            glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
            DrawString2D(5.0f, 155.0f, 0.0, "Loser!", FONT_TITLE72);
            }
        if(rEngine->state == GAME_LOADING) DrawSplash(8.0f, rEngine->stateTimer, SPLASH_PRESENTS, 0);
        if(rEngine->state == GAME_CLOSING) DrawSplash(8.0f, rEngine->stateTimer, SPLASH_RETREAT, 0);
        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        sprintf(c, "FPS: %4.2f", rEngine->gTime.GetFPS());
        if(rStats->type == PLAYER_1) DrawString2D(25.0f, height, 0.0f, c, FONT_MAIN16);

        }

    }

//=============================================================================
// DrawImage2D() - draw a menu item the quick way (premade textures)
void Interface::DrawImage2D(float x, float y, float z, GLuint *t, float w, float h)
    {
    y = height - y;                                                             // 0,0 is actually lower left
    glPushMatrix();
    glEnable(GL_TEXTURE_2D);
    Go2D();
    glBindTexture(GL_TEXTURE_2D, *t);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f,0.0f);
    glVertex3f(x, y + h, z);
    glTexCoord2f(0.0f,1.0f);
    glVertex3f(x, y, z);
    glTexCoord2f(1.0f,1.0f);
    glVertex3f(x + w, y, z);
    glTexCoord2f(1.0f,0.0f);
    glVertex3f(x + w, y + h, z);
    glEnd();
    Go3D();
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();

    }

//=============================================================================
// DrawImage3D() - draw a menu item the quick way in 3d space
void Interface::DrawImage3D(float x, float y, float z, GLuint *t, float w, float h)
    {
    glPushMatrix();
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_ALWAYS);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, *t);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f,0.0f);
    glVertex3f(x, y + (h / 40.0f), z);
    glTexCoord2f(0.0f,1.0f);
    glVertex3f(x, y, z);
    glTexCoord2f(1.0f,1.0f);
    glVertex3f(x + (w / 40.0f), y, z);
    glTexCoord2f(1.0f,0.0f);
    glVertex3f(x + (w / 40.0f), y + (h / 40.0f), z);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_DEPTH_TEST);
    glPopMatrix();
    }

//=============================================================================
// DrawString2D() - draw a string the hard way, not prerendered
void Interface::DrawString2D(float x, float y, float z, string s, int f)
    {
    y = height - y;                                                             // fix for inverted y position between opengl and sdl
    SDL_Color Color = {255, 255, 255, 255};
    SDL_Surface *Message = NULL;
    if(f == FONT_TITLE32) Message = TTF_RenderText_Blended(fontTitle32, s.c_str(), Color);
    if(f == FONT_TITLE72) Message = TTF_RenderText_Blended(fontTitle72, s.c_str(), Color);
    if(f == FONT_MAIN32)  Message = TTF_RenderText_Blended(fontMain32,  s.c_str(), Color);
    if(f == FONT_MAIN16)  Message = TTF_RenderText_Blended(fontMain16,  s.c_str(), Color);
    GLuint Texture = 0;
    //
    // lets do the opengl drawing part now
    //
    if(Message != NULL)
        {
        glPushMatrix();
        glEnable(GL_TEXTURE_2D);
        glGenTextures(1, &Texture);
        glBindTexture(GL_TEXTURE_2D, Texture);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Message->w, Message->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, Message->pixels);
        Go2D();
        glBindTexture(GL_TEXTURE_2D, Texture);
        glBegin(GL_QUADS);
        glTexCoord2f(0.0f,0.0f);
        glVertex3f(x, y + Message->h, z);
        glTexCoord2f(0.0f,1.0f);
        glVertex3f(x, y, z);
        glTexCoord2f(1.0f,1.0f);
        glVertex3f(x + Message->w, y, z);
        glTexCoord2f(1.0f,0.0f);
        glVertex3f(x + Message->w, y + Message->h, z);
        glEnd();
        Go3D();
        glDisable(GL_TEXTURE_2D);
        glPopMatrix();
        }
    //
    // clean up
    //
    glDeleteTextures(1, &Texture);
    SDL_FreeSurface(Message);

    }

//=============================================================================
// DrawString3D() - draw a string in 3d space, the hard way (not prerendered)
void Interface::DrawString3D(float x, float y, float z, string s, int f)
    {
    SDL_Color Color = {255, 255, 255, 255};                                     // opengl will handle the text color
    SDL_Surface *Message = NULL;
    if(f == FONT_TITLE32) Message = TTF_RenderText_Blended(fontTitle32, s.c_str(), Color);
    if(f == FONT_TITLE72) Message = TTF_RenderText_Blended(fontTitle72, s.c_str(), Color);
    if(f == FONT_MAIN32)  Message = TTF_RenderText_Blended(fontMain32,  s.c_str(), Color);
    if(f == FONT_MAIN16)  Message = TTF_RenderText_Blended(fontMain16,  s.c_str(), Color);
    GLuint Texture = 0;
    //
    // lets draw this as long as there is something to write
    //
    if  (Message == NULL)
        {
        cout << "Nothing to write.\n";
        }
    else
        {
        glPushMatrix();
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_ALWAYS);
        glEnable(GL_TEXTURE_2D);
        glGenTextures(1, &Texture);                                             // lets build the texture!
        glBindTexture(GL_TEXTURE_2D, Texture);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Message->w, Message->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, Message->pixels);
        glBindTexture(GL_TEXTURE_2D, Texture);
        glBegin(GL_QUADS);
        glTexCoord2f(0.0f,0.0f);
        glVertex3f(x, y + ((float)Message->h / 40.0f), z);
        glTexCoord2f(0.0f,1.0f);
        glVertex3f(x, y, z);
        glTexCoord2f(1.0f,1.0f);
        glVertex3f(x + ((float)Message->w / 40.0f), y, z);
        glTexCoord2f(1.0f,0.0f);
        glVertex3f(x + (float)(Message->w / 40.0f), y + ((float)Message->h / 40.0f), z);
        glEnd();
        glDisable(GL_TEXTURE_2D);
        glDisable(GL_DEPTH_TEST);
        glPopMatrix();
        }
    //
    // clean up
    //
    glDeleteTextures(1, &Texture);
    SDL_FreeSurface(Message);

    }

//=============================================================================
// DrawSplash() - draw a simple spash screen
void Interface::DrawSplash(float durration, float timer, int t, int extra)
    {
    if  (extra != 0)
        {
        // do some extra effect... none yet
        }
    // float ratio = (float)width / (float)height;
    float splashRatio = 1.33f; // the size of our splash screens 1024x768
    float offset = ((width / splashRatio) - height) / 2;
    if  (durration > 0.0f)
        {
        if  (timer < durration)
            {
            if  (durration - timer < 1.0f)
                {
                glColor4f(1.0f, 1.0f, 1.0f, durration - timer);
                }
            else
                {
                glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
                }
            if  (t == SPLASH_PRESENTS)
                {
                DrawImage2D(0.0f, width / splashRatio - offset, 0, &presents, width, width / splashRatio);
                }
            if  (t == SPLASH_RETREAT)
                {
                DrawImage2D(0.0f, width / splashRatio - offset, 0, &retreat, width, width / splashRatio);
                }
            }
        }
    else if (durration < 0.0f)
        {
        if  (timer > durration)
            {
            if  (timer > -1.0f)
                {
                glColor4f(1.0f, 1.0f, 1.0f, -timer);
                }
            else
                {
                glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
                }
            if  (t == SPLASH_PRESENTS)
                {
                DrawImage2D(0.0f, width / splashRatio - offset, 0, &presents, width, width / splashRatio);
                }
            if  (t == SPLASH_RETREAT)
                {
                DrawImage2D(0.0f, width / splashRatio - offset, 0, &retreat, width, width / splashRatio);
                }
            }
        }
    }

//=============================================================================
// Message() - add an in game message
void Interface::Message(string mess, Color *c)
    {
    //
    // set up the basics for the texture and sdl surface
    //
    Vertex *v = new Vertex();
    SDL_Color col = {255, 255, 255, 255}; // opengl will handle the color
    MessageItem n;
    SDL_Surface *s;
    //
    // create texture and bind it
    //
    s = TTF_RenderText_Blended(fontMain32, mess.c_str(), col);
    glGenTextures(1, &n.tex);
    glBindTexture(GL_TEXTURE_2D, n.tex);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s->w, s->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, s->pixels);
    //
    // set up other message vars
    //
    n.pos = v->Make(width / 2 - s->w / 2, height / 2 - 100.0f, 0.0f);
    n.des = v->Make(width / 2 - s->w / 2, height,              0.0f);
    n.sta = v->Make(width / 2 - s->w / 2, height / 2 - 100.0f, 0.0f);
    n.col = c->Make(c->r, c->g, c->b, c->a);
    n.wid = s->w;
    n.hei = s->h;
    messages.push_back(n);
    cout << mess << " message created.\n";
    //
    // clean house
    //
    delete v;
    SDL_FreeSurface(s);
    }

//=============================================================================
// Bubble() - add a character message bubble
void Interface::Bubble(string mess, Vertex *position, Color *c)
    {
    //
    // set up the basics for the texture and sdl surface
    //
    Vertex *v = new Vertex();
    SDL_Color Color = {255, 255, 255, 255}; // opengl will handle the color
    MessageItem n;
    SDL_Surface *s;
    //
    // create texture and bind it
    //
    s = TTF_RenderText_Blended(fontMain16, mess.c_str(), Color);
    glGenTextures(1, &n.tex);
    glBindTexture(GL_TEXTURE_2D, n.tex);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s->w, s->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, s->pixels);
    //
    // set up other bubble vars
    //
    n.pos = v->Make(position->x, position->y, position->z);
    n.des = v->Make(position->x, position->y, position->z);
    n.sta = v->Make(position->x, position->y, position->z);
    n.col = c->Make(c->r, c->g, c->b, c->a);
    n.wid = s->w;
    n.hei = s->h;
    bubble.push_back(n);
    //
    // clean house
    //
    delete v;
    SDL_FreeSurface(s);
    }

//=============================================================================
// BuildMenuItem() - build a menu item and add it to the list
void Interface::BuildMenuItem(Vertex d, string s, int action, int m)
    {
    //
    // start it up with some basic vars for makeing the texture and menu item
    //
    Vertex *v = new Vertex();
    Color *c = new Color();
    SDL_Color Color = {255, 255, 255, 255};
    MenuItem n;
    SDL_Surface *surface = NULL;
    //
    // render the text and bind texture
    //
    if(m == MENU_STATE_MM) surface = TTF_RenderText_Blended(fontMain32, s.c_str(), Color);
    if(m == MENU_STATE_GM) surface = TTF_RenderText_Blended(fontMain16, s.c_str(), Color);
    glGenTextures(1, &n.tex);
    glBindTexture(GL_TEXTURE_2D, n.tex);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
    //
    // set other menu item vars
    //
    n.pos = v->Make(0.0, (height / 2), 0.0f);
    n.des = d;
    n.sta = v->Make(0.0, (height / 2), 0.0f);
    n.col = c->Make(1.0f, 1.0f, 1.0f, 1.0f);
    n.wid = surface->w;
    n.hei = surface->h;
    n.sel = false;
    n.act = action;
    menu.push_back(n);
    }

//=============================================================================
// Move() - move user interface into place
bool Interface::Move(float d, list<MenuItem>::iterator i)
    {
    if(i->pos.x + i->des.x < d || i->pos.x - i->des.x > d) i->pos.x = i->des.x;
    else if(i->pos.x < i->des.x) i->pos.x += d * 10;
    else if(i->pos.x > i->des.x) i->pos.x -= d * 10;
    if(i->pos.y + i->des.y < d || i->pos.y - i->des.y > d) i->pos.y = i->des.y;
    else if(i->pos.y < i->des.y) i->pos.y += d * 200;
    else if(i->pos.y > i->des.y) i->pos.y -= d * 200;
    return true;
    }

//=============================================================================
// Move() - float a message around
bool Interface::Move(float d, list<MessageItem>::iterator i)
    {
    if(i->pos.x + i->des.x < d || i->pos.x - i->des.x > d) i->pos.x = i->des.x;
    else if(i->pos.x < i->des.x) i->pos.x += d * 10;
    else if(i->pos.x > i->des.x) i->pos.x -= d * 10;
    if(i->pos.y + i->des.y < d || i->pos.y - i->des.y > d) i->pos.y = i->des.y;
    else if(i->pos.y > i->des.y) i->pos.y += d * 10;
    else if(i->pos.y < i->des.y) i->pos.y -= d * 10;
    return true;
    }

//=============================================================================
// Go2D() - go to 2d drawing mode
void Interface::Go2D()
    {
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho(0, width, height, 0, -100, 100);
    glScalef(1, -1, 1);
    glTranslatef(0, -height, 0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    }

//=============================================================================
// Go3D() - switch back to 3d mode
void Interface::Go3D()
    {
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    }





